/* API function lire */
void lire(char* buffer, int length){
	/* uses the system call get_str. 
	The call is actually done using the syscall mechanism. */
	move a0, buffer
	move a1, length
	move v0, code_of_get_str
	syscall
}

/* system call */
void read_str(char* buffer, int length){
	char c;
	int i = 0;
	get_uart(pcb);
	do{
		/* calls read() from the UART module */
		c = read();
		buffer[i++] = c;
	}while(c != '\r' && i <length-1);
	release_uart();
	buffer[i] = '\0';	
}

/* UART module's function read() */
char read(){
	/* checks in the LSR register if there is some data to read */
	while(!data_ready){
		/* sets the device to generate an interrupt when data is available */
		erbfi = 1;
		/* blocks the uart owner by removing it from the ready queue
		   and calling the scheduler */
		block_owner(); 
	}
	return RBR register;
}

/* part of the interrupt handler */
if(interrupt from UART){
	if(cause == received data available)
		/* wakes the process using the device up by putting
		   the owner in the ready queue and calls the scheduler */
		wake_up_owner();
}	

/* get_uart */
void get_uart(PCB* pcb){
	/* we must disable interrupts to avoid race conditions */
	disable_interrupts();
	if(owner == NULL)
		owner = pcb;
	else
		/* the device is already in use 
		   This function removes pcb from the ready queue
		   and calls the scheduler */
		put_in_uart_queue(pcb);
	enable_interrupts();
}

/* release_uart */
void release_uart(){
	disable_interrupts();
	/* the device is no longer owned */
	owner = NULL;
	if(UART queue not empty)
		/* wakes the first process of the queue up by 
		   putting it into the ready queue and
		   calls the scheduler */
		wake_up();
	enable_interrupts();
}
